#include "shared.h"

/* WARNING - These may not actually be big enough */
static uint8 sramfile_buffer[128*1024];
static int sramfile_offset;

uLong rom_crc;

extern char *rom_human_name;

/* Battery-backed RAM saving */
int sram_read_open()
{
	char filename[14];
	void *raw_data;
	int size;

	memset(sramfile_buffer, 0, sizeof(sramfile_buffer));
	sramfile_offset = 0;

	/* Scan the first available VMU */
	maple_device_t *dev;
	dev = maple_enum_type(0, MAPLE_FUNC_MEMCARD);
	if(!dev)
	{
		printf("No VMU - Not loading\n");
		return 0;
	}

	sprintf(filename, "%08X.gps", (unsigned int)rom_crc);
	if(vmufs_read(dev, filename, &raw_data, &size) < 0)
		return 0;

	/* Parse the VMU package */
	vmu_pkg_t vmupkg;
	vmu_pkg_parse(raw_data, &vmupkg);

	/* Decompress payload */
	uLongf destLen = sizeof(sramfile_buffer);
	if(uncompress(sramfile_buffer, &destLen, vmupkg.data, vmupkg.data_len) != Z_OK)
	{
		printf("Can not decompress\n");
		return 0;
	}

	uLong payload_crc = crc32(0L, Z_NULL, 0);
	payload_crc = crc32(payload_crc, sramfile_buffer, destLen);

	/* Free memory */
	free(raw_data);

	/* Set pointer, return success */
	return 1;
}

void sram_read_close()
{
}

uint8 sram_read_uint8()
{
	return sramfile_buffer[sramfile_offset++];
}

uint16 sram_read_uint16()
{
	uint16 value;
	memcpy(&value, sramfile_buffer + sramfile_offset, sizeof(value));
	sramfile_offset += sizeof(value);
	return value;
}

uint32 sram_read_uint32()
{
	uint32 value;
	memcpy(&value, sramfile_buffer + sramfile_offset, sizeof(value));
	sramfile_offset += sizeof(value);
	return value;
}

int sram_write_open()
{
	memset(sramfile_buffer, 0, sizeof(sramfile_buffer));
	sramfile_offset = 0;
	return 1;
}

void sram_write_close()
{
	static uint8 compress_buffer[64*1024];
	uLongf destLen = sizeof(compress_buffer);

	char filename[14];
	sprintf(filename, "%08X.gps", (unsigned int)rom_crc);

	/* Look for the first available VMU */
	maple_device_t *dev;
	dev = maple_enum_type(0, MAPLE_FUNC_MEMCARD);
	if(!dev)
	{
		printf("No VMU - Not saving\n");
		return;
	}

	/* Compress data */
	if(compress2(compress_buffer, &destLen, sramfile_buffer, sramfile_offset, 9) != Z_OK)
	{
		printf("Can not compress\n");
		return;
	}

	/* Prepare a VMU package */
	vmu_pkg_t vmupkg;
	memset(&vmupkg, 0, sizeof(vmupkg));
	strncpy(vmupkg.desc_short, "Genesis Plus SRAM", 20);
	if(rom_human_name)
		strncpy(vmupkg.desc_long, rom_human_name, 36);
	else
		strncpy(vmupkg.desc_long, "Unknown Genesis Game", 36);
	strncpy(vmupkg.app_id, "Genesis Plus / DC", 20);
	vmupkg.icon_cnt = 0;
	vmupkg.data_len = destLen;
	vmupkg.data = compress_buffer;

	/* Package VMU file */
	uint8 *vmufile_raw;
	int vmufile_size;
	vmu_pkg_build(&vmupkg, &vmufile_raw, &vmufile_size);

	/* Write the data to the VMU */
	if(vmufs_write(dev, filename, vmufile_raw, vmufile_size, VMUFS_OVERWRITE) < 0)
	{
		printf("Writing failed\n");
		free(vmufile_raw);
		return;
	}

	/* Free allocated data */
	free(vmufile_raw);

	printf("VMU File Written\n");
}

void sram_write_uint8(uint8 value)
{
	sramfile_buffer[sramfile_offset++] = value;
}

void sram_write_uint16(uint16 value)
{
	memcpy(sramfile_buffer + sramfile_offset, &value, sizeof(value));
	sramfile_offset += sizeof(value);
}

void sram_write_uint32(uint32 value)
{
	memcpy(sramfile_buffer + sramfile_offset, &value, sizeof(value));
	sramfile_offset += sizeof(value);
}
